#!/bin/bash

# LifeVerse Platform 部署脚本
# 支持多环境部署和自动回滚

set -e

# 配置变量
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
DOCKER_COMPOSE_FILE="docker-compose.yml"
BACKUP_DIR="/opt/lifeverse/backups"
LOG_FILE="/var/log/lifeverse/deploy.log"

# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 日志函数
log() {
    echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE"
}

error() {
    echo -e "${RED}[ERROR]${NC} $1" | tee -a "$LOG_FILE"
}

success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1" | tee -a "$LOG_FILE"
}

warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1" | tee -a "$LOG_FILE"
}

# 显示帮助信息
show_help() {
    cat << EOF
LifeVerse Platform 部署脚本

用法: $0 [选项] <环境> <镜像标签>

环境:
    dev         开发环境
    test        测试环境
    prod        生产环境

选项:
    -h, --help              显示帮助信息
    -b, --backup            部署前创建备份
    -r, --rollback [版本]   回滚到指定版本（默认为上一个版本）
    -c, --check             仅执行健康检查
    -v, --verbose           详细输出
    --dry-run              模拟运行，不执行实际部署

示例:
    $0 dev latest                    # 部署最新版本到开发环境
    $0 prod v1.2.3 --backup        # 部署 v1.2.3 到生产环境并创建备份
    $0 --rollback v1.2.2 prod      # 回滚生产环境到 v1.2.2
    $0 --check prod                 # 检查生产环境健康状态

EOF
}

# 解析命令行参数
parse_args() {
    ENVIRONMENT=""
    IMAGE_TAG=""
    BACKUP=false
    ROLLBACK=false
    ROLLBACK_VERSION=""
    CHECK_ONLY=false
    VERBOSE=false
    DRY_RUN=false

    while [[ $# -gt 0 ]]; do
        case $1 in
            -h|--help)
                show_help
                exit 0
                ;;
            -b|--backup)
                BACKUP=true
                shift
                ;;
            -r|--rollback)
                ROLLBACK=true
                if [[ $2 && $2 != -* ]]; then
                    ROLLBACK_VERSION="$2"
                    shift
                fi
                shift
                ;;
            -c|--check)
                CHECK_ONLY=true
                shift
                ;;
            -v|--verbose)
                VERBOSE=true
                shift
                ;;
            --dry-run)
                DRY_RUN=true
                shift
                ;;
            -*)
                error "未知选项: $1"
                show_help
                exit 1
                ;;
            *)
                if [[ -z "$ENVIRONMENT" ]]; then
                    ENVIRONMENT="$1"
                elif [[ -z "$IMAGE_TAG" ]]; then
                    IMAGE_TAG="$1"
                else
                    error "过多的参数: $1"
                    show_help
                    exit 1
                fi
                shift
                ;;
        esac
    done

    # 验证参数
    if [[ -z "$ENVIRONMENT" ]]; then
        error "必须指定环境"
        show_help
        exit 1
    fi

    if [[ "$ENVIRONMENT" != "dev" && "$ENVIRONMENT" != "test" && "$ENVIRONMENT" != "prod" ]]; then
        error "无效的环境: $ENVIRONMENT"
        exit 1
    fi

    if [[ "$ROLLBACK" == false && "$CHECK_ONLY" == false && -z "$IMAGE_TAG" ]]; then
        error "必须指定镜像标签"
        show_help
        exit 1
    fi
}

# 设置环境变量
setup_environment() {
    case $ENVIRONMENT in
        dev)
            COMPOSE_FILE="docker-compose.dev.yml"
            HEALTH_URL="https://dev.lifeverse.com/api/actuator/health"
            ;;
        test)
            COMPOSE_FILE="docker-compose.test.yml"
            HEALTH_URL="https://test.lifeverse.com/api/actuator/health"
            ;;
        prod)
            COMPOSE_FILE="docker-compose.prod.yml"
            HEALTH_URL="https://lifeverse.com/api/actuator/health"
            ;;
    esac

    export LIFEVERSE_IMAGE_TAG="$IMAGE_TAG"
    export LIFEVERSE_ENVIRONMENT="$ENVIRONMENT"
}

# 健康检查
health_check() {
    local max_attempts=15
    local attempt=1

    log "执行健康检查..."

    while [[ $attempt -le $max_attempts ]]; do
        if curl -f -s "$HEALTH_URL" > /dev/null 2>&1; then
            success "健康检查通过 (尝试 $attempt/$max_attempts)"
            return 0
        fi

        warning "健康检查失败 (尝试 $attempt/$max_attempts)，30秒后重试..."
        sleep 30
        ((attempt++))
    done

    error "健康检查失败，已尝试 $max_attempts 次"
    return 1
}

# 创建备份
create_backup() {
    if [[ "$BACKUP" == false ]]; then
        return 0
    fi

    log "创建部署备份..."

    local backup_name="lifeverse-${ENVIRONMENT}-$(date +%Y%m%d-%H%M%S)"
    local backup_path="$BACKUP_DIR/$backup_name"

    if [[ "$DRY_RUN" == true ]]; then
        log "[DRY RUN] 将创建备份: $backup_path"
        return 0
    fi

    mkdir -p "$backup_path"

    # 备份当前运行的容器信息
    docker-compose -f "$COMPOSE_FILE" ps > "$backup_path/containers.txt" 2>/dev/null || true

    # 备份数据库
    if docker-compose -f "$COMPOSE_FILE" exec -T mysql mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" lifeverse > "$backup_path/database.sql" 2>/dev/null; then
        success "数据库备份完成"
    else
        warning "数据库备份失败"
    fi

    # 备份配置文件
    cp -r "$PROJECT_ROOT/config" "$backup_path/" 2>/dev/null || true

    # 记录备份信息
    cat > "$backup_path/backup_info.json" << EOF
{
    "environment": "$ENVIRONMENT",
    "timestamp": "$(date -Iseconds)",
    "current_image": "$(docker-compose -f "$COMPOSE_FILE" images -q lifeverse 2>/dev/null || echo 'unknown')",
    "backup_type": "pre_deployment"
}
EOF

    success "备份创建完成: $backup_path"
    echo "$backup_name" > "$BACKUP_DIR/latest_backup_${ENVIRONMENT}.txt"
}

# 获取上一个版本
get_previous_version() {
    local backup_file="$BACKUP_DIR/latest_backup_${ENVIRONMENT}.txt"
    if [[ -f "$backup_file" ]]; then
        cat "$backup_file"
    else
        error "找不到上一个版本信息"
        return 1
    fi
}

# 执行回滚
perform_rollback() {
    log "开始回滚操作..."

    if [[ -z "$ROLLBACK_VERSION" ]]; then
        ROLLBACK_VERSION=$(get_previous_version)
        if [[ $? -ne 0 ]]; then
            error "无法确定回滚版本"
            return 1
        fi
    fi

    log "回滚到版本: $ROLLBACK_VERSION"

    if [[ "$DRY_RUN" == true ]]; then
        log "[DRY RUN] 将回滚到版本: $ROLLBACK_VERSION"
        return 0
    fi

    local backup_path="$BACKUP_DIR/$ROLLBACK_VERSION"
    if [[ ! -d "$backup_path" ]]; then
        error "找不到备份: $backup_path"
        return 1
    fi

    # 恢复数据库
    if [[ -f "$backup_path/database.sql" ]]; then
        log "恢复数据库..."
        docker-compose -f "$COMPOSE_FILE" exec -T mysql mysql -u root -p"$MYSQL_ROOT_PASSWORD" lifeverse < "$backup_path/database.sql"
    fi

    # 恢复配置
    if [[ -d "$backup_path/config" ]]; then
        log "恢复配置文件..."
        cp -r "$backup_path/config/"* "$PROJECT_ROOT/config/"
    fi

    # 重启服务
    log "重启服务..."
    docker-compose -f "$COMPOSE_FILE" restart

    # 健康检查
    if health_check; then
        success "回滚完成"
        return 0
    else
        error "回滚后健康检查失败"
        return 1
    fi
}

# 执行部署
perform_deployment() {
    log "开始部署到 $ENVIRONMENT 环境，镜像标签: $IMAGE_TAG"

    if [[ "$DRY_RUN" == true ]]; then
        log "[DRY RUN] 将部署镜像 $IMAGE_TAG 到 $ENVIRONMENT 环境"
        return 0
    fi

    # 拉取最新镜像
    log "拉取镜像..."
    docker-compose -f "$COMPOSE_FILE" pull lifeverse

    # 停止旧服务
    log "停止旧服务..."
    docker-compose -f "$COMPOSE_FILE" stop lifeverse

    # 启动新服务
    log "启动新服务..."
    docker-compose -f "$COMPOSE_FILE" up -d lifeverse

    # 等待服务启动
    log "等待服务启动..."
    sleep 30

    # 健康检查
    if health_check; then
        success "部署完成"
        
        # 清理旧镜像
        log "清理旧镜像..."
        docker image prune -f
        
        return 0
    else
        error "部署后健康检查失败"
        
        # 自动回滚
        warning "触发自动回滚..."
        perform_rollback
        return 1
    fi
}

# 发送通知
send_notification() {
    local status=$1
    local message=$2

    if [[ -z "$NOTIFICATION_WEBHOOK" ]]; then
        return 0
    fi

    local color="good"
    case $status in
        "error") color="danger" ;;
        "warning") color="warning" ;;
    esac

    curl -X POST "$NOTIFICATION_WEBHOOK" \
        -H "Content-Type: application/json" \
        -d "{
            \"text\": \"LifeVerse Platform 部署通知\",
            \"attachments\": [{
                \"color\": \"$color\",
                \"fields\": [{
                    \"title\": \"环境\",
                    \"value\": \"$ENVIRONMENT\",
                    \"short\": true
                }, {
                    \"title\": \"状态\",
                    \"value\": \"$message\",
                    \"short\": true
                }, {
                    \"title\": \"镜像\",
                    \"value\": \"$IMAGE_TAG\",
                    \"short\": true
                }, {
                    \"title\": \"时间\",
                    \"value\": \"$(date)\",
                    \"short\": true
                }]
            }]
        }" 2>/dev/null || true
}

# 主函数
main() {
    # 创建日志目录
    mkdir -p "$(dirname "$LOG_FILE")"

    log "LifeVerse Platform 部署脚本启动"

    parse_args "$@"
    setup_environment

    if [[ "$VERBOSE" == true ]]; then
        set -x
    fi

    # 仅健康检查
    if [[ "$CHECK_ONLY" == true ]]; then
        if health_check; then
            success "健康检查通过"
            exit 0
        else
            error "健康检查失败"
            exit 1
        fi
    fi

    # 回滚操作
    if [[ "$ROLLBACK" == true ]]; then
        if perform_rollback; then
            send_notification "success" "回滚成功"
            success "回滚操作完成"
            exit 0
        else
            send_notification "error" "回滚失败"
            error "回滚操作失败"
            exit 1
        fi
    fi

    # 正常部署流程
    create_backup

    if perform_deployment; then
        send_notification "success" "部署成功"
        success "部署操作完成"
        exit 0
    else
        send_notification "error" "部署失败"
        error "部署操作失败"
        exit 1
    fi
}

# 信号处理
trap 'error "部署被中断"; exit 130' INT TERM

# 执行主函数
main "$@"